package uk.me.dewi.appenin.android.dao.db.sqlite;

import java.util.ArrayList;

import com.google.android.maps.GeoPoint;

import uk.me.dewi.appenin.android.dao.PlaceDao;
import uk.me.dewi.appenin.android.entity.Place;
import uk.me.dewi.net.rest.RestException;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class PlaceSqliteDao implements PlaceDao{
    private static final String DATABASE_TABLE = "places";
    public static final String KEY_NAME = "name";
    public static final String KEY_DESC = "description";
    public static final String KEY_ROWID = "_id";

    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;
    
    private final Context mCtx;

    /**
     * Constructor - takes the context and opens the database 
     * 
     * @param ctx the Context within which to work
     */
    public PlaceSqliteDao(Context ctx) {
        this.mCtx = ctx;
        this.open();
    }

    /**
     * Open the places database. If it cannot be opened, try to create a new
     * instance of the database. If it cannot be created, throw an exception to
     * signal the failure
     * 
     * @return this (self reference, allowing this to be chained in an
     *         initialization call)
     * @throws SQLException if the database could be neither opened or created
     */
    public PlaceSqliteDao open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }
    
    public void close() {
        mDbHelper.close();
    }


    /**
     * Create a new place using the name and description provided. If the place is
     * successfully created return the new rowId for that place, otherwise return
     * a -1 to indicate failure.
     * 
     * @param name the name of the place
     * @param description the description of the place
     * @return rowId or -1 if failed
     */
    @Override
    public Place createPlace(Place place) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(KEY_NAME, place.mName);
        initialValues.put(KEY_DESC, place.mDescription);

        place.mId = mDb.insert(DATABASE_TABLE, null, initialValues);
        return place;
    }

    /**
     * Delete the place with the given rowId
     * 
     * @param rowId id of place to delete
     * @return true if deleted, false otherwise
     */
    public boolean deletePlace(long rowId) {
        return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
    }

    /**
     * Return a Cursor over the list of all places in the database
     * 
     * @return Cursor over all places
     */
    public Cursor fetchAllPlaces() {

        return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME,
                KEY_DESC}, null, null, null, null, null);
    }

    /**
     * Return a Cursor positioned at the place that matches the given rowId
     * 
     * @param rowId id of place to retrieve
     * @return Cursor positioned to matching place, if found
     * @throws SQLException if place could not be found/retrieved
     */
    public Place fetchPlace(long rowId) throws SQLException {
        Cursor cursor = null;
        try{
            cursor =  mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
                                KEY_NAME, KEY_DESC}, KEY_ROWID + "=" + rowId, null,
                                null, null, null, null);
            if (cursor != null) {
                cursor.moveToFirst();
            }
            
            Place place = new Place();
            place.mName = cursor.getString(
                    cursor.getColumnIndexOrThrow(PlaceSqliteDao.KEY_NAME));
            place.mDescription = cursor.getString(
                    cursor.getColumnIndexOrThrow(PlaceSqliteDao.KEY_DESC));
            return place;
        }finally{
            if(cursor != null && !cursor.isClosed()){
                cursor.close();
            }
        }
    }

    /**
     * Update the place using the details provided. The place to be updated is
     * specified using the rowId, and it is altered to use the name and description
     * values passed in
     * 
     * @param rowId id of place to update
     * @param name value to set place name to
     * @param description value to set place description to
     * @return true if the place was successfully updated, false otherwise
     */
    @Override
    public boolean updatePlace(Place place) {
        ContentValues args = new ContentValues();
        args.put(KEY_NAME, place.mName);
        args.put(KEY_DESC, place.mDescription);

        return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + place.mId, null) > 0;
    }

    @Override
    public long[] getNearbyPlaceIDs(GeoPoint location, int distance)
            throws RestException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ArrayList<Place> getNearbyPlaces(GeoPoint location, int distance)
            throws RestException {
        // TODO Auto-generated method stub
        return null;
    }

}
